home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / textutl3.lha / textutils-1.3 / src / sum.c < prev    next >
C/C++ Source or Header  |  1992-06-29  |  5KB  |  216 lines

  1. /* sum -- checksum and count the blocks in a file
  2.    Copyright (C) 1986, 1989, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.    
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.    
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. */
  19.  
  20. /* Written by Kayvan Aghaiepour and David MacKenzie. */
  21.  
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <getopt.h>
  25. #include "system.h"
  26.  
  27. int bsd_sum_file ();
  28. int sysv_sum_file ();
  29. void error ();
  30.  
  31. /* The name this program was run with. */
  32. char *program_name;
  33.  
  34. /* Nonzero if any of the files read were the standard input. */
  35. int have_read_stdin;
  36.  
  37. /* Right-rotate 32-bit integer variable C. */
  38. #define ROTATE_RIGHT(c) if ((c) & 01) (c) = ((c) >>1) + 0x8000; else (c) >>= 1;
  39.  
  40. struct option longopts[] =
  41. {
  42.   {"sysv", 0, NULL, 's'},
  43.   {NULL, 0, NULL, 0}
  44. };
  45.  
  46. void
  47. main (argc, argv)
  48.      int argc;
  49.      char **argv;
  50. {
  51.   int errors = 0;
  52.   int optc;
  53.   int (*sum_func) () = bsd_sum_file;
  54.  
  55.   program_name = argv[0];
  56.   have_read_stdin = 0;
  57.  
  58.   while ((optc = getopt_long (argc, argv, "rs", longopts, (int *) 0)) != -1)
  59.     {
  60.       switch (optc)
  61.     {
  62.     case 'r':        /* For SysV compatibility. */
  63.       sum_func = bsd_sum_file;
  64.       break;
  65.  
  66.     case 's':
  67.       sum_func = sysv_sum_file;
  68.       break;
  69.  
  70.     case '?':
  71.       fprintf (stderr, "\
  72. Usage: %s [-rs] [--sysv] [file...]\n", argv[0]);
  73.       exit (1);
  74.     }
  75.     }
  76.  
  77.   if (optind == argc)
  78.     {
  79.       if ((*sum_func) ("-", 0) < 0)
  80.     errors = 1;
  81.     }
  82.   else
  83.     for (; optind < argc; optind++)
  84.       if ((*sum_func) (argv[optind], 1) < 0)
  85.     errors = 1;
  86.  
  87.   if (have_read_stdin && fclose (stdin) == EOF)
  88.     error (1, errno, "-");
  89.   exit (errors);
  90. }
  91.  
  92. /* Calculate and print the rotated checksum and the size in 1K blocks
  93.    of file FILE, or of the standard input if FILE is "-".
  94.    If PRINT_NAME is nonzero, print FILE next to the checksum and size.
  95.    The checksum varies depending on sizeof(int).
  96.    Return 0 if successful, -1 if an error occurs. */
  97.  
  98. int
  99. bsd_sum_file (file, print_name)
  100.      char *file;
  101.      int print_name;
  102. {
  103.   register FILE *fp;
  104.   register unsigned long checksum = 0; /* The checksum mod 2^16. */
  105.   register long total_bytes = 0; /* The number of bytes. */
  106.   register int ch;        /* Each character read. */
  107.  
  108.   if (!strcmp (file, "-"))
  109.     {
  110.       fp = stdin;
  111.       have_read_stdin = 1;
  112.     }
  113.   else
  114.     {
  115.       fp = fopen (file, "r");
  116.       if (fp == NULL)
  117.     {
  118.       error (0, errno, "%s", file);
  119.       return -1;
  120.     }
  121.     }
  122.  
  123.   /* This algorithm seems to depend on sign extension in `ch' in order to
  124.      give the right results.  Ick.  */
  125.   while ((ch = getc (fp)) != EOF)
  126.     {
  127.       total_bytes++;
  128.       ROTATE_RIGHT (checksum);
  129.       checksum += ch;
  130.       checksum &= 0xffff;    /* Keep it within bounds. */
  131.     }
  132.  
  133.   if (ferror (fp))
  134.     {
  135.       error (0, errno, "%s", file);
  136.       if (strcmp (file, "-"))
  137.     fclose (fp);
  138.       return -1;
  139.     }
  140.  
  141.   if (strcmp (file, "-") && fclose (fp) == EOF)
  142.     {
  143.       error (0, errno, "%s", file);
  144.       return -1;
  145.     }
  146.  
  147.   printf ("%05lu %5ld", checksum, (total_bytes + 1024 - 1) / 1024);
  148.   if (print_name)
  149.     printf (" %s", file);
  150.   putchar ('\n');
  151.  
  152.   return 0;
  153. }
  154.  
  155. /* Calculate and print the checksum and the size in 512-byte blocks
  156.    of file FILE, or of the standard input if FILE is "-".
  157.    If PRINT_NAME is nonzero, print FILE next to the checksum and size.
  158.    Return 0 if successful, -1 if an error occurs. */
  159.  
  160. int
  161. sysv_sum_file (file, print_name)
  162.      char *file;
  163.      int print_name;
  164. {
  165.   int fd;
  166.   unsigned char buf[8192];
  167.   register int bytes_read;
  168.   register unsigned long checksum = 0;
  169.   long total_bytes = 0;
  170.  
  171.   if (!strcmp (file, "-"))
  172.     {
  173.       fd = 0;
  174.       have_read_stdin = 1;
  175.     }
  176.   else
  177.     {
  178.       fd = open (file, O_RDONLY);
  179.       if (fd == -1)
  180.     {
  181.       error (0, errno, "%s", file);
  182.       return -1;
  183.     }
  184.     }
  185.  
  186.   while ((bytes_read = read (fd, buf, sizeof buf)) > 0)
  187.     {
  188.       register int i;
  189.  
  190.       for (i = 0; i < bytes_read; i++)
  191.     checksum += buf[i];
  192.       total_bytes += bytes_read;
  193.     }
  194.  
  195.   if (bytes_read < 0)
  196.     {
  197.       error (0, errno, "%s", file);
  198.       if (strcmp (file, "-"))
  199.     close (fd);
  200.       return -1;
  201.     }
  202.  
  203.   if (strcmp (file, "-") && close (fd) == -1)
  204.     {
  205.       error (0, errno, "%s", file);
  206.       return -1;
  207.     }
  208.  
  209.   printf ("%lu %ld", checksum % 0xffff, (total_bytes + 512 - 1) / 512);
  210.   if (print_name)
  211.     printf (" %s", file);
  212.   putchar ('\n');
  213.  
  214.   return 0;
  215. }
  216.